package com.haohan.cloud.scm.goods.core.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.haohan.cloud.scm.api.common.constant.IGoodsConstant;
import com.haohan.cloud.scm.api.constant.ScmCacheNameConstant;
import com.haohan.cloud.scm.api.constant.ScmCommonConstant;
import com.haohan.cloud.scm.api.constant.enums.goods.ModelAttrNameEnum;
import com.haohan.cloud.scm.api.constant.enums.opc.YesNoEnum;
import com.haohan.cloud.scm.api.goods.dto.GoodsDTO;
import com.haohan.cloud.scm.api.goods.dto.GoodsModelDTO;
import com.haohan.cloud.scm.api.goods.dto.PlatformPriceSqlDTO;
import com.haohan.cloud.scm.api.goods.entity.*;
import com.haohan.cloud.scm.api.goods.req.manage.FetchModelListReq;
import com.haohan.cloud.scm.api.goods.req.manage.GoodsPricingReq;
import com.haohan.cloud.scm.api.goods.trans.GoodsTrans;
import com.haohan.cloud.scm.api.goods.vo.GoodsModelVO;
import com.haohan.cloud.scm.api.goods.vo.GoodsVO;
import com.haohan.cloud.scm.api.manage.entity.Shop;
import com.haohan.cloud.scm.common.tools.exception.ErrorDataException;
import com.haohan.cloud.scm.common.tools.util.ScmIncrementUtil;
import com.haohan.cloud.scm.goods.core.GoodsCategoryCoreService;
import com.haohan.cloud.scm.goods.core.GoodsModelCoreService;
import com.haohan.cloud.scm.goods.service.GoodsModelService;
import com.haohan.cloud.scm.goods.service.GoodsModelTotalService;
import com.haohan.cloud.scm.goods.service.GoodsService;
import com.haohan.cloud.scm.goods.service.PlatformGoodsPriceService;
import com.haohan.cloud.scm.goods.utils.ScmGoodsUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @author dy
 * @date 2019/9/13
 */
@Service
@AllArgsConstructor
@Slf4j
public class GoodsModelCoreServiceImpl implements GoodsModelCoreService {

    private final PlatformGoodsPriceService platformGoodsPriceService;
    private final GoodsCategoryCoreService goodsCategoryCoreService;
    private final GoodsCoreBaseService baseService;
    private final GoodsModelTotalService goodsModelTotalService;
    private final GoodsModelService goodsModelService;
    private final GoodsService goodsService;
    private final ScmGoodsUtils scmGoodsUtils;
    private final ScmIncrementUtil scmIncrementUtil;

    /**
     * 名称查询, 若无对应商品则新增 商品(下架状态, 分类为  未确认商品-> 导入商品)
     *
     * @param goodsModelDTO goodsName / modelName /unit /price / shopId
     * @return
     */
    @Override
    public GoodsModelDTO fetchModelByNameOrAdd(GoodsModelDTO goodsModelDTO) {
        String shopId = goodsModelDTO.getShopId();
        // 根据 商品名称查找
        GoodsModelDTO goods = fetchModel(goodsModelDTO);
        if (null == goods) {
            Shop shop = scmGoodsUtils.fetchShopById(shopId);
            if (null == shop) {
                throw new ErrorDataException("店铺有误");
            }
            // 创建分类
            GoodsCategory category = goodsCategoryCoreService.fetchDefaultCategory(shop);
            // 创建商品
            GoodsDTO addGoods = new GoodsDTO();
            addGoods.setMerchantId(shop.getMerchantId());
            addGoods.setShopId(shopId);
            addGoods.setGoodsName(goodsModelDTO.getGoodsName());
            addGoods.setThumbUrl("default.jpg");
            addGoods.setMarketPrice(goodsModelDTO.getModelPrice());
            addGoods.setUnit(goodsModelDTO.getModelUnit());
            addGoods.setCategoryId(category.getId());
            addGoods.setIsMarketable(YesNoEnum.no);
            addGoods.setGoodsModel(YesNoEnum.no);
            // 规格列表
            GoodsModelDTO goodsModel = new GoodsModelDTO();
            goodsModel.setModelName(goodsModelDTO.getModelName());
            goodsModel.setModel("30");
            goodsModel.setModelPrice(goodsModelDTO.getModelPrice());
            goodsModel.setModelStorage(new BigDecimal(1000));
            goodsModel.setModelUnit(goodsModelDTO.getModelUnit());
            goodsModel.setModelUrl(addGoods.getThumbUrl());
            List<GoodsModelDTO> modelList = new ArrayList<>(4);
            modelList.add(goodsModel);
            addGoods.setModelList(modelList);
            // 规格名称列表
            Map<ModelAttrNameEnum, List<String>> attrMap = new HashMap<>(4);
            List<String> typeNameList = new ArrayList<>(4);
            typeNameList.add(goodsModelDTO.getModelName());
            attrMap.put(ModelAttrNameEnum.kind, typeNameList);
            addGoods.setAttrMap(attrMap);
            // 保存
            goods = GoodsTrans.createFromExt(baseService.saveGoodsWithDetail(addGoods));
        }
        return goods;
    }


    /**
     * 根据 商品名称查找,优先匹配规格名称,不匹配时 任选一条
     *
     * @param goodsModelDTO
     * @return
     */
    private GoodsModelDTO fetchModel(GoodsModelDTO goodsModelDTO) {
        String modelName = goodsModelDTO.getModelName();
        Goods goods = goodsService.fetchByName(goodsModelDTO.getShopId(), goodsModelDTO.getGoodsName());
        if (null != goods) {
            List<GoodsModel> goodsModelList = goodsModelService.fetchModelList(goods.getId());
            GoodsModel model = null;
            if (CollUtil.isNotEmpty(goodsModelList)) {
                // 匹配规格名称
                for (GoodsModel m : goodsModelList) {
                    if (StrUtil.equals(m.getModelName(), modelName)) {
                        model = m;
                        break;
                    }
                }
                if (null == model) {
                    model = goodsModelList.get(0);
                }
            } else {
                // 无规格的情况, 默认都存在规格
                model = initGoodsModel(goods, goodsModelDTO);
            }
            GoodsModelDTO result = GoodsTrans.copyFrom(goodsModelDTO, model, goods);
            // 联查平台商品定价 默认今日、平台商家
            PlatformPriceSqlDTO query = new PlatformPriceSqlDTO();
            query.setPricingPmId(scmGoodsUtils.fetchPricingPmId(goods.getShopId()));
            query.setMerchantId(scmGoodsUtils.fetchPlatformMerchant().getId());
            query.setQueryDate(LocalDate.now());
            query.setModelId(model.getId());
            GoodsTrans.modelPlatformPrice(platformGoodsPriceService.fetchOneByDate(query), result);
            return result;
        }
        return null;
    }


    /**
     * 根据商品 创建默认规格
     *
     * @param goods
     * @param goodsModelDTO
     * @return
     */
    private GoodsModel initGoodsModel(Goods goods, GoodsModelDTO goodsModelDTO) {
        GoodsModel goodsModel = new GoodsModel();
        goodsModel.setGoodsId(goods.getId());
        goodsModel.setModelName(goodsModelDTO.getModelName());
        goodsModel.setModel("30");
        goodsModel.setModelPrice(goodsModelDTO.getModelPrice());
        goodsModel.setModelStorage(new BigDecimal(1000));
        goodsModel.setModelUnit(goodsModelDTO.getModelUnit());
        goodsModel.setModelUrl(goods.getThumbUrl());
        goodsModelService.save(goodsModel);
        GoodsModelTotal modelTotal = new GoodsModelTotal();
        modelTotal.setGoodsId(goods.getId());
        modelTotal.setModelId(IGoodsConstant.GoodsModelType.type.getCode());
        modelTotal.setModelName(IGoodsConstant.GoodsModelType.type.getDesc());
        modelTotal.setSubModelId("30");
        modelTotal.setModelName(goodsModelDTO.getModelName());
        goodsModelTotalService.save(modelTotal);
        return goodsModel;
    }

    /**
     * 查询商品规格信息  根据商品名称 规格名称 规格单位
     * 优先 规格名称匹配 无时 匹配 规格单位
     * 都无 或多条匹配时 返回null
     *
     * @param goodsModelDTO 必须shopId goodsName
     * @return
     */
    @Override
    public GoodsModelDTO fetchGoodsModelByName(GoodsModelDTO goodsModelDTO) {
        String modelName = goodsModelDTO.getModelName();
        String unit = goodsModelDTO.getModelUnit();
        Goods goods = goodsService.fetchByName(goodsModelDTO.getShopId(), goodsModelDTO.getGoodsName());
        if (null == goods) {
            return null;
        }
        // 所有规格
        List<GoodsModel> goodsModelList = goodsModelService.fetchModelList(goods.getId());
        if (CollUtil.isEmpty(goodsModelList)) {
            return null;
        }
        GoodsModel model = null;
        int matchNum = 0;
        // 匹配 规格名称 和单位
        boolean nameFlag = StrUtil.isNotEmpty(modelName);
        boolean unitFlag = StrUtil.isNotEmpty(unit);
        // 优先 规格名称匹配 无时 匹配 规格单位
        for (GoodsModel m : goodsModelList) {
            if (nameFlag) {
                if (StrUtil.equals(m.getModelName(), modelName)) {
                    model = m;
                    matchNum++;
                }
            } else if (unitFlag) {
                if (StrUtil.equals(m.getModelUnit(), unit)) {
                    model = m;
                    matchNum++;
                }
            }
        }
        // 都无 或多条匹配时 返回null
        if (matchNum != 1) {
            return null;
        }
        GoodsModelDTO result = GoodsTrans.copyFrom(goodsModelDTO, model, goods);
        // 联查平台商品定价 默认今日、平台商家
        PlatformPriceSqlDTO query = new PlatformPriceSqlDTO();
        query.setPricingPmId(scmGoodsUtils.fetchPricingPmId(goods.getShopId()));
        query.setMerchantId(scmGoodsUtils.fetchPlatformMerchant().getId());
        query.setQueryDate(LocalDate.now());
        query.setModelId(model.getId());
        GoodsTrans.modelPlatformPrice(platformGoodsPriceService.fetchOneByDate(query), result);
        return result;
    }

    /**
     * 根据规格id查询商品信息
     *
     * @param goodsModelId
     * @param req          pricingDate、buyerId/pricingMerchantId或buyerId
     * @return
     */
    @Override
    public GoodsVO fetchGoodsInfoByModelId(String goodsModelId, GoodsPricingReq req) {
        GoodsModel model = goodsModelService.getById(goodsModelId);
        if (null == model) {
            throw new ErrorDataException("商品规格有误:modelId");
        }
        Goods goods = goodsService.getById(model.getGoodsId());
        if (null == goods) {
            throw new ErrorDataException("商品规格有误:goodsId");
        }
        return baseService.fetchGoodsInfo(goods, req);
    }

    /**
     * 根据规格id查询商品信息
     * 无typeName
     *
     * @param goodsModelId
     * @param req          pricingDate、  buyerId/pricingMerchantId或buyerId
     * @return
     */
    @Override
    @Cacheable(value = ScmCacheNameConstant.GOODS_MODEL_DETAIL, key = "#goodsModelId + #req")
    public GoodsModelVO fetchModelVO(String goodsModelId, GoodsPricingReq req) {
        GoodsModelDTO model = goodsModelService.getInfoById(goodsModelId);
        if (null == model) {
            throw new ErrorDataException("商品规格id有误");
        }
        // 联查平台商品定价
        PlatformPriceSqlDTO query = new PlatformPriceSqlDTO();
        query.setPricingPmId(scmGoodsUtils.fetchPricingPmId(model.getShopId()));
        query.setMerchantId(scmGoodsUtils.fetchPricingMerchantId(req.getPricingMerchantId(), req.getBuyerId()));
        query.setQueryDate(null == req.getPricingDate() ? LocalDate.now() : req.getPricingDate());
        query.setModelId(model.getId());
        PlatformGoodsPrice platformPrice = platformGoodsPriceService.fetchOneByDate(query);
        GoodsTrans.modelPlatformPrice(platformPrice, model);
        return GoodsTrans.transToVO(model);
    }

    @Override
    @Cacheable(value = ScmCacheNameConstant.GOODS_MODEL_DETAIL, key = "#page.current +'.'+ #page.size + #req")
    public IPage<GoodsModelDTO> fetchModelPage(Page<GoodsModelDTO> page, FetchModelListReq req) {
        GoodsModelDTO goodsModelDTO = req.transTo();
        // 传入modelId时处理
        String goodsModelId = goodsModelDTO.getId();
        if (StrUtil.isNotEmpty(goodsModelId)) {
            GoodsModel model = goodsModelService.getById(goodsModelId);
            if (null != model) {
                goodsModelDTO.setGoodsId(model.getGoodsId());
            } else {
                throw new ErrorDataException("商品规格id有误");
            }
        }
        IPage<GoodsModelDTO> result = goodsModelService.fetchPage(page, goodsModelDTO);
        // 联查平台商品定价
        PlatformPriceSqlDTO query = new PlatformPriceSqlDTO();
        query.setPricingPmId(scmGoodsUtils.fetchPricingPmId(req.getShopId()));
        query.setMerchantId(scmGoodsUtils.fetchPricingMerchantId(req.getPricingMerchantId(), req.getBuyerId()));
        query.setQueryDate(null == req.getPricingDate() ? LocalDate.now() : req.getPricingDate());
        result.getRecords().forEach(model -> {
            query.setModelId(model.getId());
            GoodsTrans.modelPlatformPrice(platformGoodsPriceService.fetchOneByDate(query), model);
        });
        return result;
    }

    @Override
    @Cacheable(value = ScmCacheNameConstant.GOODS_MODEL_DETAIL, key = "'info'+ #page.current +'.'+ #page.size + #req")
    public IPage<GoodsModelVO> fetchModelInfoPage(Page page, FetchModelListReq req) {
        IPage<GoodsModelDTO> modelPage = fetchModelPage(new Page<>(page.getCurrent(), page.getSize()), req);
        //  处理规格类型
        int size = Math.max(8, (int) page.getSize() * 4 / 3 + 1);
        // goodsId: <规格名称：规格类型>
        Map<String, Map<String, String>> typeMap = new HashMap<>(size);
        List<GoodsModelVO> modelList = new ArrayList<>(size);
        // 联查平台商品定价
        PlatformPriceSqlDTO query = new PlatformPriceSqlDTO();
        query.setPricingPmId(scmGoodsUtils.fetchPricingPmId(req.getShopId()));
        query.setMerchantId(scmGoodsUtils.fetchPricingMerchantId(req.getPricingMerchantId(), req.getBuyerId()));
        query.setQueryDate(null == req.getPricingDate() ? LocalDate.now() : req.getPricingDate());
        modelPage.getRecords().forEach(model -> {
            String goodsId = model.getGoodsId();
            Map<String, String> map = typeMap.get(goodsId);
            if (null == map) {
                // 商品规格类型
                // 规格名
                List<GoodsModelTotal> modelTotalList = goodsModelTotalService.fetchTotalList(goodsId);
                // 规格名称：规格类型名称
                map = modelTotalList.stream().collect(Collectors.toMap(GoodsModelTotal::getSubModelName, GoodsModelTotal::getModelName, (k1, k2) -> k1));
                typeMap.put(goodsId, map);
            }
            query.setModelId(model.getId());
            GoodsTrans.modelPlatformPrice(platformGoodsPriceService.fetchOneByDate(query), model);
            GoodsModelVO modelVO = GoodsTrans.modelTypeTrans(model.transToVO(), map);
            modelList.add(modelVO);
        });
        IPage<GoodsModelVO> result = new Page<>(modelPage.getCurrent(), modelPage.getSize(), modelPage.getTotal());
        result.setRecords(modelList);
        return result;
    }

    /**
     * 规格库存扣减
     *
     * @param modelList
     * @return
     */
    @Override
    public boolean modelStorageSubtractBatch(List<GoodsModel> modelList) {
        modelList.forEach(model -> {
            try {
                storageSubtract(model.getId(), model.getModelStorage());
            } catch (Exception e) {
                log.debug("===规格库存扣减失败, 规格id:{}, 扣减数量：{}===", model.getId(), model.getModelStorage());
            }
        });
        return true;
    }

    /**
     * 规格库存扣减
     *
     * @param modelId
     * @param num     扣减数量
     */
    private void storageSubtract(String modelId, BigDecimal num) {
        if (StrUtil.isEmpty(modelId) || null == num) {
            throw new ErrorDataException("modelId,num参数有误");
        }
        // 缓存中获取数量
        BigDecimal storage = fetchModelStorage(modelId);
        storage = storage.subtract(num);
        // 缓存中修改数量
        modifyModelStorage(modelId, storage);
        // 数据库保存
        GoodsModel update = new GoodsModel();
        update.setId(modelId);
        update.setModelStorage(storage);
        goodsModelService.updateById(update);
        // 刷新商品缓存
//        GoodsModel exist = checkModel(modelId);
//        goodsService.flushGoodsCacheById(exist.getGoodsId());
    }

    /**
     * 缓存中获取库存数量
     *
     * @param modelId
     * @return
     */
    private BigDecimal fetchModelStorage(String modelId) {
        // key:modelId
        String existStorage = scmIncrementUtil.fetchValue(ScmCommonConstant.MODEL_STORAGE_KEY.concat(modelId));
        if (StrUtil.isEmpty(existStorage)) {
            GoodsModel model = checkModel(modelId);
            modifyModelStorage(modelId, model.getModelStorage());
            return model.getModelStorage();
        }
        return new BigDecimal(existStorage);
    }

    /**
     * 缓存中修改数量, 有效时间1小时
     *
     * @param modelId
     * @param storage
     */
    private void modifyModelStorage(String modelId, BigDecimal storage) {
        scmIncrementUtil.setValue(ScmCommonConstant.MODEL_STORAGE_KEY.concat(modelId), storage.toString(), 3600);
    }

    @Override
    public boolean changeStorage(String modelId, BigDecimal storage) {
        // 修改缓存规格库存值
        modifyModelStorage(modelId, storage);
        GoodsModel update = new GoodsModel();
        update.setId(modelId);
        update.setModelStorage(storage);
        goodsModelService.updateById(update);
        // 刷新商品缓存
//        GoodsModel exist = checkModel(modelId);
//        goodsService.flushGoodsCacheById(exist.getGoodsId());
        return true;
    }

    private GoodsModel checkModel(String modelId) {
        GoodsModel exist = goodsModelService.getById(modelId);
        if (null == exist) {
            throw new ErrorDataException("商品规格有误:modelId");
        }
        return exist;
    }
}
